package com.tcfvic.client.panels.widgets.widgetcontents;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Hyperlink;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.tcfvic.client.PersonService;
import com.tcfvic.client.PersonServiceAsync;
import com.tcfvic.client.panels.widgets.SimpleMessagePopup;
import com.tcfvic.client.panels.widgets.TCFWidgetContent;
import com.tcfvic.client.pojos.Course;
import com.tcfvic.client.pojos.Person;
import com.tcfvic.client.pojos.Personcourse;
import com.tcfvic.client.pojos.PersoncourseId;
import com.tcfvic.client.pojos.Qualification;
import com.tcfvic.client.pojos.Rto;
import com.tcfvic.client.tools.Month;
import com.tcfvic.client.tools.Tools;

public class TrainingTab extends AbstractDataEntryWidgets implements
		TCFWidgetContent {

	/**
	 * Create a remote service proxy to talk to the server-side PersonDetails
	 * service.
	 */
	private final PersonServiceAsync personService = GWT
			.create(PersonService.class);
	private FlexTable trainingTable = null;
	private FlexTable tabContentFlexTable = null;
	// private Map<Integer, List<Personcourse>> personCoursesByFundingID = new
	// HashMap<Integer, List<Personcourse>>();
	private List<Course> courses = new ArrayList<Course>();
	private Map<Integer, Rto> rtos = new HashMap<Integer, Rto>();
	private Map<Integer, Qualification> qualifications = new HashMap<Integer, Qualification>();
	private String currentPersonRowId = "";

	public TrainingTab() {
		// initialise();
	}

	public String getName() {
		return "Training";
	}

	@Override
	public Widget getContent() {
		final Button moveToRight = new Button("Add training");

		// Create a table to layout the form options
		tabContentFlexTable = new FlexTable();
		tabContentFlexTable.setCellSpacing(3);
		tabContentFlexTable.setWidth("100%");

		moveToRight.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				addTraining(Integer.valueOf(0), "", "", "", null, null, false);
			}
		});
		moveToRight.ensureDebugId("cwBasicButton-normal");

		// add buttons panel to flex table
		tabContentFlexTable.setWidget(0, 0, moveToRight);

		setupTrainingList();

		// SAVE button
		saveButton.getElement().setId("saveButton");
		tabContentFlexTable.setWidget(3, 0, saveButton);

		return tabContentFlexTable;
	}

	public void setupTrainingList() {
		// Create a Flex Table
		int col = 0;
		FlexTable flexTable = new FlexTable();
		flexTable.addStyleName("cw-FlexTable");
		flexTable.setWidth("32em");
		flexTable.setCellSpacing(1);
		flexTable.setCellPadding(1);
		// flexTable.setHTML(0, col++, "ID");
		// col++; // increasing col number because I have commented out the
		// above
		// line
		flexTable.setHTML(0, col++, "Course No");
		flexTable.setHTML(0, col++, "Course name");
		// flexTable.setHTML(0, col++, "Course type");
		flexTable.setHTML(0, col++, "RTO");
		flexTable.setHTML(0, col++, "Start date");
		flexTable.setHTML(0, col++, "Finish date");
		flexTable.setHTML(0, col++, "Completed");
		flexTable.setHTML(0, col++, "Action");

		flexTable.setBorderWidth(1);
		trainingTable = flexTable;

		tabContentFlexTable.setWidget(1, 0, trainingTable);
		tabContentFlexTable.getFlexCellFormatter().setColSpan(1, 0, 4);
	}

	public void addTraining(Integer courseId, String courseName,
			String qualification, String rto, Date startDate, Date finishDate,
			boolean completed) {
		final int numRows = trainingTable.getRowCount();

		int col = 0;

		trainingTable.setWidget(numRows, col++, new HTML(String
				.valueOf(numRows)));

		ListBox lb = getCourseList(courseName);
		// lb.setSelectedIndex(Tools.getSelectedIndex(lb, courseName));
		trainingTable.setWidget(numRows, col++, lb);

		// lb = getQualificationList();
		// lb.setSelectedIndex(Tools.getSelectedIndex(lb, qualification));
		// HTML courseType = new HTML(qualification);
		// trainingTable.setWidget(numRows, col++, courseType);

		lb = getRTOList();
		lb.setSelectedIndex(Tools.getSelectedIndexBasedOnItem(lb, rto));
		trainingTable.setWidget(numRows, col++, lb);

		// start date
		HorizontalPanel hp = new HorizontalPanel();
		ListBox dayStart = Tools.getDayListBox();
		ListBox monthStart = Tools.getMonthListBox();
		ListBox yearStart = Tools.getYearListBox(2009);
		hp.add(dayStart);
		hp.add(monthStart);
		hp.add(yearStart);
		try {
			dayStart.setSelectedIndex(Tools.getSelectedIndexBasedOnItem(
					dayStart, Tools.getDay(startDate)));
			monthStart.setSelectedIndex(Month.valueOf(
					Tools.getMonth(startDate).toUpperCase()).getId());
			yearStart.setSelectedIndex(Tools.getSelectedIndex(yearStart, Tools
					.getYear(startDate)));
		} catch (Exception e) {
		}
		trainingTable.setWidget(numRows, col++, hp);

		// finish date
		hp = new HorizontalPanel();
		dayStart = Tools.getDayListBox();
		monthStart = Tools.getMonthListBox();
		yearStart = Tools.getYearListBox(2009);
		hp.add(dayStart);
		hp.add(monthStart);
		hp.add(yearStart);
		try {
			dayStart.setSelectedIndex(Tools.getSelectedIndexBasedOnItem(
					dayStart, Tools.getDay(finishDate)));
			monthStart.setSelectedIndex(Month.valueOf(
					Tools.getMonth(finishDate).toUpperCase()).getId());
			yearStart.setSelectedIndex(Tools.getSelectedIndex(yearStart, Tools
					.getYear(finishDate)));
		} catch (Exception e) {
		}
		trainingTable.setWidget(numRows, col++, hp);

		// completed
		lb = Tools.getYesNoList();
		if (completed) {
			lb.setSelectedIndex(1);
		} else {
			lb.setSelectedIndex(2);
		}
		trainingTable.setWidget(numRows, col++, lb);

		Hyperlink link = new Hyperlink("Remove", String.valueOf(numRows));
		link.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				Hyperlink link = (Hyperlink) event.getSource();
				removeRow(link.getTargetHistoryToken());
			}
		});
		trainingTable.setWidget(numRows, col++, link);
	}

	private ListBox getCourseList(String courseName) {
		ListBox lb = new ListBox();
		lb.addItem("", "");
		for (Course course : courses) {
			String courseType = "";
			if (course.getCourseType() != null
					&& course.getCourseType().trim().length() > 0) {
				courseType = " - " + course.getCourseType();
			}
			lb.addItem(course.getName() + courseType, String.valueOf(course
					.getId()));
			if (course.getName().equals(courseName)) {
				lb.setSelectedIndex(lb.getItemCount() - 1);
			}
		}
		return lb;
	}

	private ListBox getRTOList() {
		ListBox lb = new ListBox();
		lb.addItem("", "");
		for (Rto rto : rtos.values()) {
			lb.addItem(rto.getName() + " - " + rto.getCampus(), String.valueOf(rto.getId()));
		}
		return lb;
	}

	private void populateQualificationList(ListBox lb) {
		ListBox newLb = getQualificationList();
		lb.clear();
		for (int i = 0; i < newLb.getItemCount(); i++) {
			lb.addItem(newLb.getItemText(i), newLb.getValue(i));
		}
	}

	private ListBox getQualificationList() {
		final ListBox lb = new ListBox();
		lb.addItem("", "");
		lb.addItem("-------------", "line1");
		lb.addItem("Add new qualification", "Add new qualification");
		lb.addItem("-------------", "line2");
		for (Qualification q : qualifications.values()) {
			lb.addItem(q.getName(), String.valueOf(q.getId()));
		}

		final TextBox qualNameToCreate = new TextBox();
		final DialogBox dialogBox = createDialogBoxForQual(qualNameToCreate, lb);
		lb.addChangeHandler(new ChangeHandler() {
			@Override
			public void onChange(ChangeEvent event) {
				ListBox lb = (ListBox) event.getSource();
				if (lb.getSelectedIndex() > 0) {
					if (lb.getItemText(lb.getSelectedIndex()).equals(
							"Add new qualification")) {
						dialogBox.center();
						dialogBox.show();
					}
				}
			}
		});

		return lb;
	}

	/**
	 * Create the dialog box for this example.
	 * 
	 * @return the new dialog box
	 */
	private DialogBox createDialogBoxForQual(final TextBox levelNameToCreate,
			final ListBox listBoxSource) {
		// Create a dialog box and set the caption text
		final DialogBox dialogBox = new DialogBox();
		dialogBox.ensureDebugId("cwDialogBox");
		dialogBox.setText("Create qualification");

		// Create a table to layout the content
		VerticalPanel dialogContents = new VerticalPanel();
		dialogContents.setSpacing(4);
		dialogBox.setWidget(dialogContents);

		// Add some text to the top of the dialog
		HTML details = new HTML(
				"This box is to create qualification for eg. \"Certificate II\"");
		dialogContents.add(details);
		dialogContents.setCellHorizontalAlignment(details,
				HasHorizontalAlignment.ALIGN_CENTER);

		HorizontalPanel hp = new HorizontalPanel();
		details = new HTML("Enter qualification name:");
		hp.add(details);
		hp.add(levelNameToCreate);
		dialogContents.add(hp);
		dialogContents.setCellHorizontalAlignment(details,
				HasHorizontalAlignment.ALIGN_CENTER);

		// BUTTONS
		hp = new HorizontalPanel();
		// Add a save button at the bottom of the dialog
		Button saveButton = new Button("Save", new ClickHandler() {
			public void onClick(ClickEvent event) {
				if (levelNameToCreate.getText() == null
						|| levelNameToCreate.getText().trim().length() == 0) {
					new SimpleMessagePopup(
							"Please enter qualification before trying to save",
							null).showPopup();
				} else {
					saveQualToDatabaseAndRefresh(levelNameToCreate.getValue(),
							listBoxSource);
				}
				dialogBox.hide();
			}
		});
		hp.add(saveButton);
		// Add a close button at the bottom of the dialog
		Button closeButton = new Button("Cancel", new ClickHandler() {
			public void onClick(ClickEvent event) {
				dialogBox.hide();
			}
		});
		hp.add(closeButton);
		dialogContents.add(hp);
		dialogContents.setCellHorizontalAlignment(hp,
				HasHorizontalAlignment.ALIGN_RIGHT);

		if (LocaleInfo.getCurrentLocale().isRTL()) {
			dialogContents.setCellHorizontalAlignment(closeButton,
					HasHorizontalAlignment.ALIGN_LEFT);

		} else {
			dialogContents.setCellHorizontalAlignment(closeButton,
					HasHorizontalAlignment.ALIGN_RIGHT);
		}

		// Return the dialog box
		return dialogBox;
	}

	private void saveQualToDatabaseAndRefresh(String name, final Object source) {
		Qualification q = new Qualification();
		q.setName(name);
		personService.saveQualification(q, new AsyncCallback<Void>() {
			@Override
			public void onSuccess(Void result) {
				updateQualificationsList(source);
			}

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Error adding qualification to database", caught);
			}
		});

	}

	// /**
	// * Populate the cell with the initial funding amount
	// *
	// * @param box
	// */
	// private void populateFundingInitialAmount(ListBox box) {
	// Integer rowId = Integer.valueOf(box.getValue(box.getSelectedIndex())
	// .split(idDelimiter)[0]);
	// if (box.getValue(box.getSelectedIndex()) != null
	// && box.getValue(box.getSelectedIndex()).length() > 0) {
	// if (box.getValue(box.getSelectedIndex()).split(idDelimiter)[1]
	// .equals("+1")) {
	// trainingTable.setHTML(getRowNumber(rowId), 3, "");
	// } else {
	// Integer id = Integer.valueOf(box.getValue(
	// box.getSelectedIndex()).split(idDelimiter)[1]);
	// trainingTable.setHTML(getRowNumber(rowId), 3, String
	// .valueOf(personFundingSources.get(id)
	// .getFundingsource().getInitialamount()));
	// }
	// }
	// }

	// /**
	// * Calculate the funding amount available and place this in the cell
	// *
	// * @param box
	// */
	// private void populateFundingAvailable(ListBox box) {
	// Integer rowId = Integer.valueOf(box.getValue(box.getSelectedIndex())
	// .split(idDelimiter)[0]);
	// if (box.getValue(box.getSelectedIndex()) != null
	// && box.getValue(box.getSelectedIndex()).length() > 0) {
	// if (box.getValue(box.getSelectedIndex()).split(idDelimiter)[1]
	// .equals("+1")) {
	// trainingTable.setHTML(getRowNumber(rowId), 3, "");
	// } else {
	// Integer id = Integer.valueOf(box.getValue(
	// box.getSelectedIndex()).split(idDelimiter)[1]);
	// List<Personcourse> pcList = personCoursesByFundingID.get(id);
	// long total = 0;
	// if (pcList != null) {
	// for (Personcourse pc : pcList) {
	// total += pc.getCost();
	// }
	// }
	// long amountRemaining = personFundingSources.get(id)
	// .getFundingsource().getInitialamount()
	// - total;
	//
	// trainingTable.setHTML(getRowNumber(rowId), 4, String
	// .valueOf(amountRemaining));
	// }
	// }
	// }

	// private Integer getRowNumber(Integer searchRowId) {
	// for (int i = 1; i < trainingTable.getRowCount(); i++) {
	// if (trainingTable.getHTML(i, 0).split(idDelimiter)[0]
	// .equals(searchRowId.toString())) {
	// return i;
	// }
	// }
	// return null;
	// }

	private void removeRow(String id) {
		for (int i = 1; i < trainingTable.getRowCount(); i++) {
			HTML rowID = (HTML) trainingTable.getWidget(i, 0);
			if (rowID.getText().equals(id)) {
				trainingTable.removeRow(i);
				break;
			}
		}
	}

	public void clear() {
		while (trainingTable.getRowCount() > 1) {
			trainingTable.removeRow(1);
		}
	}

	public void updateContent(Object o) {
		if (o != null) {
			Person p = (Person) o;
			currentPersonRowId = String.valueOf(p.getId());
			initialise();
		}
	}

	private void updateQualificationsList(final Object source) {
		personService
				.getAllQualifications(new AsyncCallback<List<Qualification>>() {
					@Override
					public void onSuccess(List<Qualification> result) {
						qualifications = new HashMap<Integer, Qualification>();
						for (Qualification q : result) {
							qualifications.put(q.getId(), q);
						}
						if (source != null && source instanceof ListBox) {
							populateQualificationList((ListBox) source);
						}
					}

					@Override
					public void onFailure(Throwable caught) {
						new SimpleMessagePopup(
								"Error occured getting the qual list " + caught,
								null).showPopup();
						GWT.log("Error occured getting the quallist: " + caught
								+ "!---", caught);
					}
				});
	}

	@Override
	public void initialise() {
		updateQualificationsList(null);
		personService.getAllTraining(new AsyncCallback<List<Course>>() {
			@Override
			public void onSuccess(List<Course> result) {
				courses = new ArrayList<Course>();
				for (Course course : result) {
					courses.add(course);
				}
				// populateTrainingList();
			}

			@Override
			public void onFailure(Throwable caught) {
				new SimpleMessagePopup(
						"Error occured getting the training list " + caught,
						null).showPopup();
				GWT.log("Error occured getting the training list: " + caught
						+ "!---", caught);
			}
		});
		personService.getAllRTOs(new AsyncCallback<List<Rto>>() {
			@Override
			public void onSuccess(List<Rto> result) {
				rtos = new HashMap<Integer, Rto>();
				for (Rto rto : result) {
					rtos.put(rto.getId(), rto);
				}
			}

			@Override
			public void onFailure(Throwable caught) {
				new SimpleMessagePopup("Error occured getting the rto list "
						+ caught, null).showPopup();
				GWT.log("Error occured getting the rto list: " + caught
						+ "!---", caught);
			}
		});
		if (currentPersonRowId.length() > 0) {
			personService.getPersonCourseDetails(Integer
					.valueOf(currentPersonRowId),
					new AsyncCallback<List<Personcourse>>() {
						@Override
						public void onSuccess(List<Personcourse> result) {
							List<Personcourse> personCourses = new ArrayList<Personcourse>();
							for (Personcourse pc : result) {
								// populate personCourse hash
								personCourses.add(pc);
							}
							populateTrainingEnroled(personCourses);
						}

						@Override
						public void onFailure(Throwable caught) {
							new SimpleMessagePopup(
									"Error occured getting the person-course data",
									null).showPopup();
						}
					});
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> T saveContent(T t) throws NumberFormatException, Exception {
		Set<Personcourse> personCourses = null;
		if (trainingTable.getRowCount() > 1) {
			personCourses = new HashSet<Personcourse>();
			for (int i = 1; i < trainingTable.getRowCount(); i++) {
				Personcourse personCourse = new Personcourse();
				// get course id
				ListBox courseList = (ListBox) trainingTable.getWidget(i, 1);
				String id = courseList.getValue(courseList.getSelectedIndex());
				if (id != null && !id.isEmpty()) {
					personCourse.setId(new PersoncourseId(0, 0, Integer
							.valueOf(id)));
				} else {
					continue;
				}

				// // get qual
				// try {
				// ListBox qual = (ListBox) trainingTable.getWidget(i, 2);
				// Integer qualId = Integer.valueOf(qual.getValue(qual
				// .getSelectedIndex()));
				// personCourse.setQualification(qualifications.get(qualId));
				// } catch (Exception e) {
				// }

				// get rto
				try {
					ListBox rto = (ListBox) trainingTable.getWidget(i, 2);
					Integer rtoId = Integer.valueOf(rto.getValue(rto
							.getSelectedIndex()));
					personCourse.setRto(rtos.get(rtoId));
				} catch (Exception e) {
				}

				// get start date
				HorizontalPanel hp = (HorizontalPanel) trainingTable.getWidget(
						i, 3);
				ListBox day = (ListBox) hp.getWidget(0);
				ListBox month = (ListBox) hp.getWidget(1);
				ListBox year = (ListBox) hp.getWidget(2);
				if (Tools.isValidDate(day, month, year)) {
					personCourse.setTrainingdate(Tools.parseDate(day, month,
							year));
				}

				// get finish date
				hp = (HorizontalPanel) trainingTable.getWidget(i, 4);
				day = (ListBox) hp.getWidget(0);
				month = (ListBox) hp.getWidget(1);
				year = (ListBox) hp.getWidget(2);
				if (Tools.isValidDate(day, month, year)) {
					personCourse.setFinishDate(Tools
							.parseDate(day, month, year));
				}

				// get completed
				ListBox cb = (ListBox) trainingTable.getWidget(i, 5);
				personCourse.setCompleted(cb.getSelectedIndex() == 1 ? "true"
						: "false");
				personCourses.add(personCourse);
			}
		}
		return (T) personCourses;
	}

	public void populateTrainingEnroled(final List<Personcourse> personCourses) {
		if (personCourses != null) {
			for (Personcourse course : personCourses) {
				boolean completed = Boolean.valueOf(course.getCompleted());
				String qualification = "";
				String rto = "";
				if (course.getCourse() != null) {
					try {
						qualification = Tools.getCourseType(
								course.getCourse().getCourseType()).getType();
					} catch (Exception e) {
					}
				}
				if (course.getRto() != null) {
					rto = String.valueOf(course.getRto().getId());
				}
				addTraining(course.getCourse().getId(), course.getCourse()
						.getName(), qualification, rto, course
						.getTrainingdate(), course.getFinishDate(), completed);
			}
		}
	}

	public PersonServiceAsync getPersonService() {
		return personService;
	}

	@Override
	public void createNewRecord() {
		// TODO Auto-generated method stub

	}

}
